 /*******************************************************************************
  * Copyright (c) 2004, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal.progress;

 import java.util.ArrayList ;
 import java.util.List ;

 import org.eclipse.core.runtime.Assert;
 import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.viewers.IBaseLabelProvider;
 import org.eclipse.jface.viewers.ILabelProvider;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.DisposeEvent;
 import org.eclipse.swt.events.DisposeListener;
 import org.eclipse.swt.events.PaintEvent;
 import org.eclipse.swt.events.PaintListener;
 import org.eclipse.swt.graphics.FontMetrics;
 import org.eclipse.swt.graphics.GC;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.graphics.Transform;
 import org.eclipse.swt.widgets.Canvas;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Widget;
 import org.eclipse.ui.internal.TrimUtil;

 /**
  * The ProgressCanvasViewer is the viewer used by progress windows. It displays text
  * on the canvas.
  */
 public class ProgressCanvasViewer extends AbstractProgressViewer {
     Canvas canvas;

     Object [] displayedItems = new Object [0];

     private final static List EMPTY_LIST = new ArrayList ();

     /**
      * Font metrics to use for determining pixel sizes.
      */
     private FontMetrics fontMetrics;

     private int numShowItems = 1;

     private int maxCharacterWidth;

     private int orientation = SWT.HORIZONTAL;

     /**
      * Create a new instance of the receiver with the supplied
      * parent and style bits.
      * @param parent The composite the Canvas is created in
      * @param style style bits for the canvas
      * @param itemsToShow the number of items this will show
      * @param numChars The number of characters for the width hint.
      * @param side the side to display text, this helps determine horizontal vs vertical
      */
     ProgressCanvasViewer(Composite parent, int style, int itemsToShow, int numChars, int orientation) {
         super();
         this.orientation = orientation;
         numShowItems = itemsToShow;
         maxCharacterWidth = numChars;
         canvas = new Canvas(parent, style);
         hookControl(canvas);
         // Compute and store a font metric
 GC gc = new GC(canvas);
         gc.setFont(JFaceResources.getDefaultFont());
         fontMetrics = gc.getFontMetrics();
         gc.dispose();
         initializeListeners();
     }

     /**
      * NE: Copied from ContentViewer. We don't want the OpenStrategy hooked
      * in StructuredViewer.hookControl otherwise the canvas will take focus
      * since it has a key listener. We don't want this included in the window's
      * tab traversal order. Defeating it here is more self-contained then
      * setting the tab list on the shell or other parent composite.
      */
     protected void hookControl(Control control) {
         control.addDisposeListener(new DisposeListener() {
             public void widgetDisposed(DisposeEvent event) {
                 handleDispose(event);
             }
         });
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.StructuredViewer#doFindInputItem(java.lang.Object)
      */
     protected Widget doFindInputItem(Object element) {
         return null; // No widgets associated with items
 }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.StructuredViewer#doFindItem(java.lang.Object)
      */
     protected Widget doFindItem(Object element) {
         return null; // No widgets associated with items
 }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.StructuredViewer#doUpdateItem(org.eclipse.swt.widgets.Widget,
      * java.lang.Object, boolean)
      */
     protected void doUpdateItem(Widget item, Object element, boolean fullMap) {
         canvas.redraw();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.StructuredViewer#getSelectionFromWidget()
      */
     protected List getSelectionFromWidget() {
         //No selection on a Canvas
 return EMPTY_LIST;
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.StructuredViewer#internalRefresh(java.lang.Object)
      */
     protected void internalRefresh(Object element) {
         displayedItems = getSortedChildren(getRoot());
         canvas.redraw();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.StructuredViewer#reveal(java.lang.Object)
      */
     public void reveal(Object element) {
         //Nothing to do here as we do not scroll
 }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.StructuredViewer#setSelectionToWidget(java.util.List,
      * boolean)
      */
     protected void setSelectionToWidget(List l, boolean reveal) {
         //Do nothing as there is no selection
 }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.Viewer#getControl()
      */
     public Control getControl() {
         return canvas;
     }

     private void initializeListeners() {
         canvas.addPaintListener(new PaintListener() {
             /*
              * (non-Javadoc)
              *
              * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent)
              */
             public void paintControl(PaintEvent event) {

                 GC gc = event.gc;
                 Transform transform = null;
                 if (orientation == SWT.VERTICAL) {
                     transform = new Transform(event.display);
                     transform.translate(TrimUtil.TRIM_DEFAULT_HEIGHT, 0);
                     transform.rotate(90);
                 }
                 ILabelProvider labelProvider = (ILabelProvider) getLabelProvider();

                 int itemCount = Math.min(displayedItems.length, numShowItems);

                 int yOffset = 0;
                 int xOffset = 0;
                 if (numShowItems == 1) {//If there is a single item try to center it
 Rectangle clientArea = canvas.getParent().getClientArea();
                     if (orientation == SWT.HORIZONTAL) {
                         int size = clientArea.height;
                         yOffset = size - (fontMetrics.getHeight());
                         yOffset = yOffset / 2;
                     } else {
                         int size = clientArea.width;
                         xOffset = size - (fontMetrics.getHeight());
                         xOffset = xOffset / 2;
                     }
                 }

                 for (int i = 0; i < itemCount; i++) {
                     String string = labelProvider.getText(displayedItems[i]);
                     if(string == null) {
                         string = "";//$NON-NLS-1$
 }
                     if (orientation == SWT.HORIZONTAL) {
                         gc.drawString(string, 2, yOffset + (i * fontMetrics.getHeight()), true);
                     } else {
                         gc.setTransform(transform);
                         gc.drawString(string, xOffset + (i * fontMetrics.getHeight()), 2, true);
                     }
                 }
                 if (transform != null)
                     transform.dispose();
             }
         });
     }

     /* (non-Javadoc)
      * @see org.eclipse.jface.viewers.ContentViewer#setLabelProvider(org.eclipse.jface.viewers.IBaseLabelProvider)
      */
     public void setLabelProvider(IBaseLabelProvider labelProvider) {
         Assert.isTrue(labelProvider instanceof ILabelProvider);
         super.setLabelProvider(labelProvider);
     }

     /**
      * Get the size hints for the receiver. These are used for
      * layout data.
      * @return Point - the preferred x and y coordinates
      */
     public Point getSizeHints() {

         Display display = canvas.getDisplay();

         GC gc = new GC(canvas);
         FontMetrics fm = gc.getFontMetrics();
         int charWidth = fm.getAverageCharWidth();
         int charHeight = fm.getHeight();
         int maxWidth = display.getBounds().width / 2;
         int maxHeight = display.getBounds().height / 6;
         int fontWidth = charWidth * maxCharacterWidth;
         int fontHeight = charHeight * numShowItems;
         if (maxWidth < fontWidth) {
             fontWidth = maxWidth;
         }
         if (maxHeight < fontHeight) {
             fontHeight = maxHeight;
         }
         gc.dispose();
         return new Point(fontWidth, fontHeight);
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.progress.AbstractProgressViewer#add(java.lang.Object[])
      */
     public void add(Object [] elements) {
         refresh(true);
         
     }

     /* (non-Javadoc)
      * @see org.eclipse.ui.internal.progress.AbstractProgressViewer#remove(java.lang.Object[])
      */
     public void remove(Object [] elements) {
         refresh(true);
         
     }


 }

